package ru.ifmo.swing.genetics.spring;

import org.springframework.beans.factory.annotation.Required;
import org.uncommons.watchmaker.framework.*;
import ru.ifmo.common.Source;
import ru.ifmo.genetics.adaptation.AdaptableParameter;
import ru.ifmo.genetics.adaptation.GenerationalAdaptingEvolutionEngine;

import java.util.List;
import java.util.Random;

/**
 * @author avhaliullin
 */
public class EvolutionProcess implements Runnable {
    private CandidateFactory<String> candidateFactory;
    private EvolutionaryOperator<String> evolutionScheme;
    private FitnessEvaluator<String> fitnessEvaluator;
    private SelectionStrategy<String> selectionStrategy;
    private Random rng;
    private Source<Integer> populationSizeSource;
    private Source<Integer> elitismSource;
    private EvolutionObserver<String> evolutionObserver;
    private TerminationCondition terminationCondition;
    private List<AdaptableParameter<String>> adaptableParameters;

    public void run() {
        EvolutionEngine<String> engine = new GenerationalAdaptingEvolutionEngine<String>(
                candidateFactory,
                evolutionScheme,
                fitnessEvaluator,
                selectionStrategy,
                rng,
                adaptableParameters
        );
        if (evolutionObserver != null) {
            engine.addEvolutionObserver(evolutionObserver);
        }
        engine.evolve(populationSizeSource.create(), elitismSource.create(), terminationCondition);
    }

    @Required
    public void setCandidateFactory(CandidateFactory<String> candidateFactory) {
        this.candidateFactory = candidateFactory;
    }

    @Required
    public void setEvolutionScheme(EvolutionaryOperator<String> evolutionScheme) {
        this.evolutionScheme = evolutionScheme;
    }

    @Required
    public void setFitnessEvaluator(FitnessEvaluator<String> fitnessEvaluatorSource) {
        this.fitnessEvaluator = fitnessEvaluatorSource;
    }

    @Required
    public void setSelectionStrategy(SelectionStrategy<String> selectionStrategy) {
        this.selectionStrategy = selectionStrategy;
    }

    @Required
    public void setRng(Random rng) {
        this.rng = rng;
    }

    @Required
    public void setPopulationSizeSource(Source<Integer> populationSizeSource) {
        this.populationSizeSource = populationSizeSource;
    }

    @Required
    public void setElitismSource(Source<Integer> elitismSource) {
        this.elitismSource = elitismSource;
    }

    public void setEvolutionObserver(EvolutionObserver<String> evolutionObserver) {
        this.evolutionObserver = evolutionObserver;
    }

    @Required
    public void setTerminationCondition(TerminationCondition terminationCondition) {
        this.terminationCondition = terminationCondition;
    }

    public void setAdaptableParameters(List<AdaptableParameter<String>> adaptableParameters) {
        this.adaptableParameters = adaptableParameters;
    }
}
